package com.repro.lib_base.liveData

import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import java.lang.Exception
import java.lang.NullPointerException




object HookLiveDataVersionUtils {

    /**要修改observer.mLastVersion的值那么思考：（逆向思维）
     * mLastVersion-》observer-》iterator.next().getValue()-》mObservers
     * 反射使用的时候，正好相反
     *
     * mObservers-》函数（iterator.next().getValue()）-》observer-》mLastVersion
     * 通过hook，将observer.mLastVersion = mVersion
     * @param observer
     * @throws Exception
     */
    @Throws(Exception::class)
    fun <T>hook(observer: Observer<T>) {
        //get wrapper's version
        val classLiveData = LiveData::class.java
        val fieldObservers = classLiveData.getDeclaredField("mObservers")
        fieldObservers.isAccessible = true
        val objectObservers = fieldObservers[this]

        val classObservers: Class<*> = objectObservers.javaClass
        val methodGet = classObservers.getDeclaredMethod("get", Any::class.java)
        methodGet.isAccessible = true
        val objectWrapperEntry = methodGet.invoke(objectObservers, observer)

        var objectWrapper: Any? = null
        if (objectWrapperEntry is Map.Entry<*, *>) {
            objectWrapper = objectWrapperEntry.value
        }
        if (objectWrapper == null) {
            throw NullPointerException("Wrapper can not be bull!")
        }
        val classObserverWrapper: Class<*> = objectWrapper.javaClass.superclass
        val fieldLastVersion = classObserverWrapper.getDeclaredField("mLastVersion")
        fieldLastVersion.isAccessible = true
        //get livedata's version
        val fieldVersion = classLiveData.getDeclaredField("mVersion")
        fieldVersion.isAccessible = true
        val objectVersion = fieldVersion[this]
        //set wrapper's version
        fieldLastVersion[objectWrapper] = objectVersion
    }

}